//===============================================================================
// Microsoft patterns & practices
// Web Client Software Factory
//-------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//-------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================
using System;
using System.Web.Security;
using System.Web;
using System.Globalization;

namespace WCSFContrib.PageFlow.Storage.EnterpriseLibrary
{
	/// <summary>
	/// An implementation of the <see cref="IPageFlowCorrelationTokenProvider">IPageFlowCorrelationTokenProvider</see>
	/// that uses a cookie based token used by an <see cref="IPageFlowInstanceStore">IPageFlowInstanceStore</see> 
	/// to match a user to a PageFlow instance.
	/// </summary>
	public class CookiePageFlowCorrelationTokenProvider : IPageFlowCorrelationTokenProvider
	{
        private const string PageFlowAnonymousTokenCookieName = ".PAGEFLOWANONYMOUSTOKEN";
        private const string PageFlowAuthenticatedTokenCookieName = ".PAGEFLOWAUTHTOKEN";

		/// <summary>
		/// Retrieves a correlation token for the current user.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String">String</see> based token for the current user.
		/// </returns>
		/// <remarks>
		///	For authenticated users, a token containing a <see cref="Guid">Guid</see> and the user identity is created.
		/// For non-authenticated users, a token based on a Guid is created.
		/// </remarks>
        public string GetCorrelationToken()
        {
            if (Request.IsAuthenticated)
            {
                return GetAuthenticatedToken();
            }
            else
            {
                return GetAnonymousToken();
            }
        }

        private string GetAuthenticatedToken()
        {
            string authenticatedToken;
            HttpCookie authenticatedCookie = GetOrCreateCookie(PageFlowAuthenticatedTokenCookieName, GenerateAuthenticatedToken());
            authenticatedToken = authenticatedCookie.Value;

            string identity = authenticatedToken.Substring(authenticatedToken.IndexOf('_') + 1);
            if (!identity.Equals(HttpContext.Current.User.Identity.Name, StringComparison.CurrentCultureIgnoreCase))
            {
                authenticatedCookie.Value = GenerateAuthenticatedToken();
                Response.Cookies.Add(authenticatedCookie);
                authenticatedToken = authenticatedCookie.Value;
            }
            return authenticatedToken;
        }

        private string GetAnonymousToken()
        {
            string anonymousToken;
            if (AnonymousIdentificationModule.Enabled)
            {
                anonymousToken = Request.AnonymousID;
            }
            else
            {
                HttpCookie anonymousCookie = GetOrCreateCookie(PageFlowAnonymousTokenCookieName, Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture));
                anonymousToken = anonymousCookie.Value;
            }
            return anonymousToken;
        }

        private static string GenerateAuthenticatedToken()
        {
            return Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture) + "_" + HttpContext.Current.User.Identity.Name;
        }

        private HttpCookie GetOrCreateCookie(string name, string value)
        {
            HttpCookie cookie = Request.Cookies[name];
            if (cookie == null)
            {
                cookie = new HttpCookie(name, value);
                cookie.Expires = DateTime.MaxValue;
                Response.Cookies.Add(cookie);
            }
            return cookie;
        }

        private HttpRequest Request
        {
            get { return HttpContext.Current.Request; }
        }

        private HttpResponse Response
        {
            get { return HttpContext.Current.Response; }
        }
	}
}
